class ByteArray {
    data: ArrayBuffer;
    dataView: DataView;
    pos: number = 0;
    length: number = 0;
    constructor(data: ArrayBuffer) {
        this.data = data;
        this.dataView = new DataView(data);
        this.pos = 0;
        this.length = this.dataView.byteLength;
    }


    readByte(): number {
        var d = this.dataView.getInt8(this.pos);
        this.pos += 1;
        return d;
    }
    readShort(): number {
        var d = this.dataView.getInt16(this.pos);
        this.pos += 2;
        return d;
    }
    readInt(): number {
        var d = this.dataView.getInt32(this.pos);
        this.pos += 4;
        return d;
    }
    readUnsignedInt(): number {
        var d = this.dataView.getUint32(this.pos);
        this.pos += 4;
        return d;
    }
    readStr(): string {
        var len = this.dataView.getUint16(this.pos);
        this.pos += 2;
        var arr = [];
        for (var i = 0; i < len; i++) {
            arr[i] = this.dataView.getUint8(this.pos + i);
        }
        this.pos += len;
        return String.fromCharCode.apply(null, arr);
    }
    readString() {
        var totalByte = this.readShort();
        var readByte = 0;
        var out = [];
        var len = 0;
        var sum;
        for (; ;) {
            var t = null;
            if (readByte < totalByte) {
                t = this.dataView.getUint8(this.pos);
                this.pos = this.pos + 1;
                readByte = readByte + 1;
            }

            var ac = false;
            if (t) {
                var tt = t - 128;
                if (0 <= tt && tt < 64) {
                    sum <<= 6;
                    sum |= tt;
                    ac = true
                }
            }
            if (!ac) {
                if (sum) {
                    if (sum < 65536) {
                        out[len++] = sum;
                    }
                    else {
                        sum -= 65536;
                        out[len++] = sum >> 10 | 0xd800;
                        out[len++] = sum & 1023 | 0xdc00;
                    }
                }
                if (t) {
                    var pow = 128;
                    if (247 < t) {
                        throw "error";
                    }
                    for (; ;) {
                        if (t < pow) {
                            sum = t;
                            break
                        }
                        t = t - pow;
                        pow >>= 1
                    }
                }
                else {
                    break
                }
            }
        }
        return String.fromCharCode.apply(null, out)
    }
    readBlob(len: number): Blob {
        let fragment = this.data.slice(this.pos, this.pos + len);

        var blob: Blob;
        try {
            blob = new Blob([fragment], { type: "application/octet-binary" });
        } catch (e) {
            var win: any = window;
            win.BlobBuilder = win.BlobBuilder ||
                win.WebKitBlobBuilder ||
                win.MozBlobBuilder ||
                win.MSBlobBuilder;
            if (e.name == 'TypeError' && win.BlobBuilder) {
                var bb = new win.BlobBuilder();
                bb.append(fragment);
                blob = bb.getBlob("image/png");
            }

        }

        this.pos += len;
        return blob;
    }

}